/**
 * Copyright (c) 2016, 2024, All rights reserved.
 * Powered by [liangyafeng@duplicall.com] On 2024-03-25 16:22:17
 */
package com.yafengliang.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yafengliang.config.AmplitudeEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Controller;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.sound.sampled.*;
import java.io.*;
import java.nio.file.Files;

/**
 * <p>Project: SpringBoot - RecordController
 * <p>@Author: liangyafeng@duplicall.com On 2024-03-25 16:22:17
 *
 * <p>@Description:
 */
@Controller
@Slf4j
public class RecordController {

    private TargetDataLine targetDataLine;
    private File audioFile;
    private final String audioPath; // 录音文件保存路径
    private final String asrUrl;    // 语音识别url

    @Autowired
    private RestTemplate restTemplate;


    public RecordController(
            @Value("${vclog.audio.path}") String audioPath,
            @Value("${vclog.asr.url}") String asrUrl
    ) {
        this.audioPath = audioPath;
        this.asrUrl = asrUrl;
        this.targetDataLine = null;
        this.audioFile = null;
    }

    /**
     * 跳转首页
     *
     * @return 跳转首页
     */
    @GetMapping("/")
    public String toIndex() {
        return "/index";
    }

    @GetMapping(value = "dialog")
    public String toDialog() {
        return "/dialog";
    }

    @GetMapping(value = "/microphone")
    public String ToMicrophone() {
        return "/microphone";
    }

    /**
     * 开始录音
     *
     * @return 开始录音
     */
    @RequestMapping(value = "startRecording", method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<String> startRecording() {
        try {
            AudioFormat audioFormat = new AudioFormat(
                    44100,
                    16,
                    1,
                    true,
                    false);
            DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);

            if (!AudioSystem.isLineSupported(dataLineInfo)) {
                return ResponseEntity.badRequest().body("Microphone not supported");
            }

            targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
            targetDataLine.open(audioFormat);
            targetDataLine.start();

            File dir = new File(audioPath);
            Files.createDirectories(dir.toPath());
            String fileName = System.currentTimeMillis() + ".wav";
            audioFile = new File(dir, fileName);
            Thread recordingThread = new Thread(() -> {
                byte[] buffer = new byte[1024];
                while (targetDataLine.isOpen()){
                    int bytesRead = targetDataLine.read(buffer, 0, buffer.length);
                    if (bytesRead > 0) {
                        // 计算音频振幅
                        double amplitude = calculateAmplitude(buffer, bytesRead);
                        String json = "{'amplitude',"+amplitude+"}";
                        // 发送 amplitude 到前端
                        // ...
                        AmplitudeEndpoint.sendAmplitude(json);
                    }
                }
                try (AudioInputStream audioInputStream = new AudioInputStream(targetDataLine)) {
                    AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, audioFile);


                } catch (IOException e) {
                    log.error("Failed to save file: {}", e.getMessage());
                }
            });
            recordingThread.start();
            return ResponseEntity.ok("Start recording...");
        } catch (LineUnavailableException | IOException e) {
            log.error("Unable to start recording：{}", e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("Unable to start recording: " + e.getMessage());
        }
    }

    /**
     * 停止录音
     *
     * @return 停止录音
     */
    @PostMapping(value = "stopRecording")
    @ResponseBody
    public ResponseEntity<String> stopRecording() {
        MultipartFile multipartFile = null;
        if (targetDataLine != null) {
            targetDataLine.stop();
            targetDataLine.close();
        }

        if (audioFile != null) {
            try {
                FileInputStream inputStream = new FileInputStream(audioFile);
                multipartFile = new MockMultipartFile("file", audioFile.getName(), "audio/wav", inputStream);
                String processedRecording = processRecording(multipartFile);
                if (!processedRecording.isEmpty()) {
                    log.info("Processed recording: {}", processedRecording);
                    return ResponseEntity.ok(processedRecording);
                } else {
                    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                            .body("Error connecting to ASR");
                }
            } catch (IOException e) {
                log.error("Failed to process the recording file: {}", e.getMessage());
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                        .body("Error processing the recording file");
            } finally {
                if (multipartFile != null && multipartFile.getSize()>0) {
                    // 删除临时文件
                    File tempFile = multipartFileToFile(multipartFile);
                    if (tempFile != null) {
                        boolean deleted = tempFile.delete();
                        if (!deleted) {
                            log.warn("Failed to delete temporary file: {}", tempFile.getAbsolutePath());
                        }
                    }
                }
                // 删除保存文件
                //boolean deleted = audioFile.delete();
                //if (!deleted) {
                //    log.warn("Failed to delete audioFile file: {}", audioFile.getAbsolutePath());
                //}
            }
        }
        return ResponseEntity.badRequest().body("Error, the recording file does not exist");
    }

    /**
     * 处理录音文件
     *
     * @param multipartFile 文件
     * @return 文字结果
     */
    private String processRecording(MultipartFile multipartFile) {
        File file = multipartFileToFile(multipartFile);
        FileSystemResource resource = new FileSystemResource(file);
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.add("audio", resource);
        map.add("language", "zh");

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);

        ResponseEntity<String> responseEntity = restTemplate.postForEntity(asrUrl, requestEntity, String.class);
        return mergeTexts(responseEntity.getBody());
    }

    @PostMapping(value = "stopRecord")
    @ResponseBody
    public String uploadFile(@RequestParam(value = "audio")MultipartFile audio){
        // 创建RestTemplate实例
        RestTemplate restTemplate = new RestTemplate();
        File file = multipartFileToFile(audio);
        // 目标URL
        String url = "http://192.168.6.174:8000/asr/trans";
        // 创建MultiValueMap来存储文件和其他参数
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        // 添加文件
        FileSystemResource files = new FileSystemResource(file);
        body.add("audio", files);
        // 如果需要添加其他参数
        body.add("language", "zh");
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        // 创建HttpEntity
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
        // 发送请求
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, requestEntity, String.class);
        log.debug("responseEntity.getBody:{}", responseEntity.getBody());
        // 处理响应
        String mergeTexts = "";
        responseEntity.getBody();
        if (!responseEntity.getBody().isEmpty()) {
            mergeTexts = mergeTexts(responseEntity.getBody());
        }
        return mergeTexts;
    }


    /**
     * MultipartFile 转 File
     *
     * @param multipartFile MultipartFile 对象
     * @return File 对象
     */
    private static File multipartFileToFile(MultipartFile multipartFile) {
        if (multipartFile.isEmpty() || multipartFile.getSize() <= 0) {
            return null;
        }
        try {
            File tempFile = File.createTempFile("temp-", ".wav");
            try (InputStream inputStream = multipartFile.getInputStream();
                 OutputStream outputStream = Files.newOutputStream(tempFile.toPath())) {
                //tempFile = File.createTempFile("temp-", ".wav");
                IOUtils.copy(inputStream, outputStream);
            }
            return tempFile;
        } catch (IOException e) {
            log.error("Error converting MultipartFile to File: {}", e.getMessage());
            throw new RuntimeException("Error converting MultipartFile to File", e);
        }
    }


    /**
     * 返回结果合并
     */
    private static String mergeTexts(String jsonStr) {
        try {
            JSONObject jsonObject = JSON.parseObject(jsonStr);
            if (!jsonObject.containsKey("data")) {
                throw new IllegalArgumentException("Missing 'data' field in input JSON");
            }

            JSONArray data = jsonObject.getJSONArray("data");
            StringBuilder mergedTextBuilder = new StringBuilder();

            for (int i = 0; i < data.size(); i++) {
                JSONObject item = data.getJSONObject(i);
                if (!item.containsKey("text")) {
                    throw new IllegalArgumentException("Missing 'text' field in one of the items in 'data' array");
                }
                String text = item.getString("text");
                mergedTextBuilder.append(text).append(" ");
            }

            return mergedTextBuilder.toString().trim();
        } catch (Exception e) {
            throw new RuntimeException("Error merging text from JSON using Fastjson", e);
        }
    }


    /**
     * 计算音频的振幅。
     * @param buffer
     * @param bytesRead
     * @return
     */
    private double calculateAmplitude(byte[] buffer, int bytesRead) {
        long sum = 0;
        for (int i = 0; i < bytesRead - 1; i += 2) {
            // 将两个字节转换为16位整数
            short sample = (short) ((buffer[i + 1] << 8) | (buffer[i] & 0xff));
            sum += Math.abs(sample);
        }
        // 计算平均振幅
        return (double) sum / ((double) bytesRead / 2);
    }

    public static void main(String[] args) {
        String json = "{\"code\": 0, \"msg\": \"success\", \"data\": [{\"start\": 0.88, \"end\": 2.16, \"text\": \"HELLO 大家好,我是CHAO\", \"role\": \"U\"}, {\"start\": 3.46, \"end\": 5.04, \"text\": \"今天,我们要来看一部\", \"role\": \"U\"}, {\"start\": 5.04, \"end\": 5.22, \"text\": \"最新的电影\", \"role\": \"U\"}]}\n";
        String mergeTexts = mergeTexts(json);
        log.info(mergeTexts);
    }


}
